﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using NetPE.TreeNodes;
using System.Reflection;
using NetPE.Core.DataDirectories;
using NetPE.Core.Metadata;
using System.Globalization;
using NetPE.Core;
using NetPE.Dialogs;
using System.Collections.ObjectModel;

namespace NetPE
{
    public class CLREditor : BaseEditor
    {
        CLRDNode n;
        TableLayoutPanel panel;
        public CLREditor(CLRDNode n)
        {
            this.n = n;
            this.DoubleBuffered = true;
            panel = new TableLayoutPanel();
            panel.ColumnCount = 2;
            panel.Location = Point.Empty;
            panel.AutoSize = true;
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200));
            panel.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
            panel.Padding = new Padding(5);
            this.Controls.Add(panel);
        }

        protected override void RefreshData()
        {
            panel.SuspendLayout();
            panel.Controls.Clear();

            PropertyInfo[] info = new PropertyInfo[] { typeof(CLRDirectory).GetProperty("Size"),
                                                       typeof(CLRDirectory).GetProperty("MajorRuntimeVersion"),
                                                       typeof(CLRDirectory).GetProperty("MinorRuntimeVersion"),
                                                       typeof(CLRDirectory).GetProperty("Flags")};
            panel.RowCount = 6;
            panel.Controls.Add(new Label() { Text = "Name", Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 0, 0);
            panel.Controls.Add(new Label() { Text = "Value", Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 1, 0);

            TextBox tb;
            for (int i = 0; i < info.Length; i++)
            {
                panel.Controls.Add(new Label() { Text = info[i].Name, Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 0, i + 1);
              
                switch (info[i].PropertyType.FullName)
                {
                    case "NetPE.Core.Rva":
                        tb = new TextBox();
                        tb.BackColor = Color.Black;
                        tb.ForeColor = Color.White;
                        tb.BorderStyle = BorderStyle.None;
                        tb.TextAlign = HorizontalAlignment.Center;
                        tb.Width = 200;
                        tb.Anchor = AnchorStyles.None;
                        tb.Text = info[i].GetValue(Object, null).ToString();
                        tb.LostFocus += new EventHandler(PropChanged);
                        tb.Tag = info[i];
                        panel.Controls.Add(tb, 1, i + 1);
                        break;
                    case "System.UInt16":
                        tb = new TextBox();
                        tb.BackColor = Color.Black;
                        tb.ForeColor = Color.White;
                        tb.BorderStyle = BorderStyle.None;
                        tb.TextAlign = HorizontalAlignment.Center;
                        tb.Width = 200;
                        tb.Anchor = AnchorStyles.None;
                        tb.Text = ((ushort)info[i].GetValue(Object, null)).ToString("x4");
                        tb.LostFocus += new EventHandler(PropChanged);
                        tb.Tag = info[i];
                        panel.Controls.Add(tb, 1, i + 1);
                        break;
                    case "System.UInt32":
                        tb = new TextBox();
                        tb.BackColor = Color.Black;
                        tb.ForeColor = Color.White;
                        tb.BorderStyle = BorderStyle.None;
                        tb.TextAlign = HorizontalAlignment.Center;
                        tb.Width = 200;
                        tb.Anchor = AnchorStyles.None;
                        tb.Text = ((uint)info[i].GetValue(Object, null)).ToString("x8");
                        tb.LostFocus += new EventHandler(PropChanged);
                        tb.Tag = info[i];
                        panel.Controls.Add(tb, 1, i + 1);
                        break;
                    default:
                        Button btn = new Button();
                        btn.FlatStyle = FlatStyle.Popup;
                        btn.Anchor = AnchorStyles.None;
                        btn.Dock = DockStyle.Fill;
                        btn.Text = info[i].PropertyType.Name;
                        btn.Click += new EventHandler(ShowEditDialog);
                        btn.Tag = info[i];
                        panel.Controls.Add(btn, 1, i + 1);
                        break;
                }
            }

            panel.Controls.Add(new Label() { Text = "EntryPoint", Dock = DockStyle.Fill, AutoSize = false, TextAlign = ContentAlignment.MiddleCenter }, 0, 5);
            if (((CLRDirectory.RuntimeFlags)typeof(CLRDirectory).GetProperty("Flags").GetValue(Object, null) & CLRDirectory.RuntimeFlags.NativeEntryPoint) == CLRDirectory.RuntimeFlags.NativeEntryPoint)
            {
                tb = new TextBox();
                tb.BackColor = Color.Black;
                tb.ForeColor = Color.White;
                tb.BorderStyle = BorderStyle.None;
                tb.TextAlign = HorizontalAlignment.Center;
                tb.Width = 200;
                tb.Anchor = AnchorStyles.None;
                tb.Text = typeof(CLRDirectory).GetProperty("EntryPointCodes").GetValue(Object, null).ToString();
                tb.LostFocus += new EventHandler(PropChanged);
                panel.Controls.Add(tb, 1, 5);
            }
            else
            {
                tb = new TextBox();
                tb.BackColor = Color.Black;
                tb.ForeColor = Color.White;
                tb.BorderStyle = BorderStyle.None;
                tb.TextAlign = HorizontalAlignment.Center;
                tb.Width = 200;
                tb.Anchor = AnchorStyles.None;
                tb.Text = ((MetadataToken)typeof(CLRDirectory).GetProperty("EntryPointToken").GetValue(Object, null)).Value.ToString("x8");
                tb.LostFocus += new EventHandler(PropChanged);
                panel.Controls.Add(tb, 1, 5);
            }

            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));
            panel.ResumeLayout();
        }

        bool onevent = false;
        private void PropChanged(object sender, EventArgs e)
        {
            if (!onevent)
            {
                string val = (sender as Control).Text;
                if ((sender as Control).Tag == null)
                {
                    bool isRva = (((CLRDirectory.RuntimeFlags)typeof(CLRDirectory).GetProperty("Flags").GetValue(Object, null) & CLRDirectory.RuntimeFlags.NativeEntryPoint) == CLRDirectory.RuntimeFlags.NativeEntryPoint);
                   
                    if (isRva)
                    {
                        if (val.TrimStart('0').Length <= 8)
                            typeof(CLRDirectory).GetProperty("EntryPointCodes").SetValue(Object, (Rva)uint.Parse(val, NumberStyles.HexNumber), null);
                    }
                    else
                    {
                        if (val.TrimStart('0').Length <= 8)
                            typeof(CLRDirectory).GetProperty("EntryPointToken").SetValue(Object, new MetadataToken(uint.Parse(val, NumberStyles.HexNumber)), null);
                    }

                    onevent = true;
                    if (isRva)
                    {
                        (sender as Control).Text = typeof(CLRDirectory).GetProperty("EntryPointCodes").GetValue(Object, null).ToString();
                    }
                    else
                    {
                        (sender as Control).Text = ((MetadataToken)typeof(CLRDirectory).GetProperty("EntryPointToken").GetValue(Object, null)).Value.ToString("x8");
                    }
                    onevent = false;
                }

                PropertyInfo prop = (sender as Control).Tag as PropertyInfo;

                switch (prop.PropertyType.FullName)
                {
                    case "NetPE.Core.Rva":
                        if (val.TrimStart('0').Length > 8) break;
                        break;
                    case "System.UInt16":
                        if (val.TrimStart('0').Length > 4) break;
                        prop.SetValue(Object, ushort.Parse(val, NumberStyles.HexNumber), null);
                        break;
                    case "System.UInt32":
                        if (val.TrimStart('0').Length > 8) break;
                        prop.SetValue(Object, uint.Parse(val, NumberStyles.HexNumber), null);
                        break;
                    default: throw new InvalidOperationException();
                }

                onevent = true;
                switch (prop.PropertyType.FullName)
                {
                    case "NetPE.Core.Rva":
                        (sender as Control).Text = prop.GetValue(Object, null).ToString();
                        break;
                    case "System.UInt16":
                        (sender as Control).Text = ((ushort)prop.GetValue(Object, null)).ToString("x4");
                        break;
                    case "System.UInt32":
                        (sender as Control).Text = ((uint)prop.GetValue(Object, null)).ToString("x8");
                        break;
                    default: throw new InvalidOperationException();
                }
                onevent = false;
            }
        }

        private void ShowEditDialog(object sender, EventArgs e)
        {
            PropertyInfo i = (sender as Control).Tag as PropertyInfo;
            BaseDialog dialog = null;

            if (i.PropertyType.IsEnum)
            {
                if (i.PropertyType.IsDefined(typeof(FlagsAttribute), true))
                    (dialog = new FlagEnumDialog(i.GetValue(Object, null))).ShowDialog();
                else
                    (dialog = new EnumDialog(i.GetValue(Object, null))).ShowDialog();
            }

            if (i.CanWrite)
                i.SetValue(Object, dialog.Object, null);
        
            bool isRva = (((CLRDirectory.RuntimeFlags)typeof(CLRDirectory).GetProperty("Flags").GetValue(Object, null) & CLRDirectory.RuntimeFlags.NativeEntryPoint) == CLRDirectory.RuntimeFlags.NativeEntryPoint);

            onevent = true;
            if (isRva)
            {
                panel.GetControlFromPosition(1, 5).Text = typeof(CLRDirectory).GetProperty("EntryPointCodes").GetValue(Object, null).ToString();
            }
            else
            {
                panel.GetControlFromPosition(1, 5).Text = ((MetadataToken)typeof(CLRDirectory).GetProperty("EntryPointToken").GetValue(Object, null)).Value.ToString("x8");
            }
            onevent = false;
        }
    }
}
